package com.winhxd.b2c.customer.service.impl;

import com.winhxd.b2c.common.cache.Cache;
import com.winhxd.b2c.common.domain.customer.enums.*;
import com.winhxd.b2c.common.domain.order.enums.OrderRebateStatusEnum;
import com.winhxd.b2c.customer.config.PayWithdrawalConfig;
import com.winhxd.b2c.common.constant.BusinessCode;
import com.winhxd.b2c.common.constant.CacheName;
import com.winhxd.b2c.common.constant.PayNotifyMsg;
import com.winhxd.b2c.common.context.CustomerUser;
import com.winhxd.b2c.common.domain.customer.bo.CustomerRevenueBO;
import com.winhxd.b2c.common.domain.customer.condition.CustomerApplyWithDrawCondition;
import com.winhxd.b2c.common.domain.customer.condition.ShoppingMallRuleCondition;
import com.winhxd.b2c.common.domain.customer.model.*;
import com.winhxd.b2c.common.domain.customer.vo.CustomerRevenueVO;
import com.winhxd.b2c.common.domain.customer.vo.CustomerWithdrawalsInfoVO;
import com.winhxd.b2c.common.domain.customer.vo.ShoppingMallRuleVO;
import com.winhxd.b2c.common.domain.message.condition.MiniTemplateData;
import com.winhxd.b2c.common.domain.message.enums.MiniMsgTypeEnum;
import com.winhxd.b2c.common.domain.order.model.OrderRebateRecord;
import com.winhxd.b2c.common.domain.order.vo.OrderInfoVO;
import com.winhxd.b2c.common.domain.order.vo.OrderRebateRecordVO;
import com.winhxd.b2c.common.exception.BusinessException;
import com.winhxd.b2c.common.feign.order.OrderServiceClient;
import com.winhxd.b2c.common.util.JsonUtil;
import com.winhxd.b2c.common.util.MessageSendUtils;
import com.winhxd.b2c.customer.dao.CustomerUserInfoMapper;
import com.winhxd.b2c.customer.dao.CustomerWalletMapper;
import com.winhxd.b2c.customer.dao.CustomerWithdrawalsMapper;
import com.winhxd.b2c.customer.service.*;
import com.winhxd.b2c.customer.util.SendMsgUtil;
import com.winhxd.b2c.customer.util.TemplateData;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author caiyulong
 */
@Service
public class CustomerRevenueServiceImpl implements CustomerRevenueService {

    private static final Logger logger = LoggerFactory.getLogger(CustomerRevenueServiceImpl.class);

    @Autowired
    private Cache cache;

    @Autowired
    private CustomerWalletService customerWalletService;

    @Autowired
    private OrderServiceClient orderServiceClient;

    @Autowired
    private CustomerIntegralDetailService customerIntegralDetailService;

    @Autowired
    private CustomerRevenueDetailService customerRevenueDetailService;

    @Autowired
    private CustomerWithdrawalsMapper customerWithdrawalsMapper;

    @Autowired
    private PayWithdrawalConfig payWithdrawalConfig;

    @Autowired
    private ShoppingMallRuleService shoppingMallRuleService;

    @Autowired
    private CustomerWalletMapper customerWalletMapper;

    @Autowired
    private CustomerUserInfoMapper customerUserInfoMapper;

    @Autowired
    MessageSendUtils messageSendUtils;


    @Override
    public CustomerRevenueVO getCustomerRevenue(Long customerId, Integer level) {
        logger.info("查询我的收益积分入参：customerId={}, level={}", customerId, level);
        CustomerRevenueVO customerRevenueVO = new CustomerRevenueVO();
        CustomerRevenueBO customerRevenueBO = getCustomerRevenueCache(customerId, level);
        if (customerRevenueBO != null) {
            BeanUtils.copyProperties(customerRevenueBO, customerRevenueVO);
        }
        logger.info("查询我的收益积分返参：{}", JsonUtil.toJSONString(customerRevenueVO));
        return customerRevenueVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void orderClosedCalculateRevenue(OrderRebateRecordVO orderRebateRecordVO) {
        if (Objects.isNull(orderRebateRecordVO)){
            return;
        }
        String orderNo = orderRebateRecordVO.getOrderNo();
        List<OrderRebateRecord> orderRebateRecordList = orderRebateRecordVO.getOrderRebateRecordList();
        //判断订单时间是否重复消费
        List<CustomerRevenueDetail> customerRevenueDetailList = customerRevenueDetailService.findCustomerRevenueDetailByOrderNo(orderNo);
        if (CollectionUtils.isNotEmpty(customerRevenueDetailList)){
            logger.info("#收益计算# - 订单重复消费 orderNo=" + orderNo);
            return;
        }
        logger.info("#收益计算# - 开始计算 orderNo=" + orderNo);
        long start = System.currentTimeMillis();
        OrderInfoVO orderInfoVO = orderServiceClient.getOrderInfoByOrderNo(orderNo).getDataWithException();
        if (Objects.isNull(orderInfoVO)) {
            logger.error("#收益计算# - 订单服务查询订单信息为null  orderNo=" + orderNo);
            return;
        }
        if (CollectionUtils.isEmpty(orderRebateRecordList)) {
            logger.error("#收益计算# - MQ传入订单返利记录为null  orderNo=" + orderNo);
            return;
        }
        //添加用户收益流水及钱包
        customerCalculateRevenue(orderRebateRecordList, orderInfoVO);
        logger.info("#收益计算# - 结束计算 orderNo=" + orderNo + "耗时：" + (System.currentTimeMillis() - start)/1000);
    }

    private void customerCalculateRevenue(List<OrderRebateRecord> orderRebateRecordVOList, OrderInfoVO orderInfoVO) {
        //积分流水
        List<CustomerIntegralDetail> customerIntegralDetailList = new ArrayList<>();
        //收益流水
        List<CustomerRevenueDetail> customerRevenueDetailList = new ArrayList<>();
        //用于计算下线收益的一级分销商id
        Long firstCustomerId = Objects.isNull(orderInfoVO.getTwoAgent()) ? null : orderInfoVO.getFirstAgent();
        orderRebateRecordVOList.stream().filter(orderRebateRecord -> OrderRebateStatusEnum.HAH_CORRECTION.getStatusCode() == orderRebateRecord.getStatus()).forEach(orderRebateRecordVO -> {
            //一级分销商
            if (Objects.nonNull(orderInfoVO.getFirstAgent())){
                CustomerIntegralDetail firstCustomerIntegralDetail = jointFirstCustomerIntegralDetail(orderRebateRecordVO, orderInfoVO);
                customerIntegralDetailList.add(firstCustomerIntegralDetail);
                CustomerRevenueDetail firstCustomerRevenueDetail = jointFirstCustomerRevenueDetail(orderRebateRecordVO, orderInfoVO);
                customerRevenueDetailList.add(firstCustomerRevenueDetail);
            }

            //二级分销商
            if (Objects.nonNull(orderInfoVO.getTwoAgent())){
                CustomerIntegralDetail twoCustomerIntegralDetail = jointTwoCustomerIntegralDetail(orderRebateRecordVO, orderInfoVO);
                customerIntegralDetailList.add(twoCustomerIntegralDetail);
                CustomerRevenueDetail twoCustomerRevenueDetail = jointTwoCustomerRevenueDetail(orderRebateRecordVO, orderInfoVO);
                customerRevenueDetailList.add(twoCustomerRevenueDetail);
            }

            //会员
            if (Objects.nonNull(orderInfoVO.getCustomerId())){
                CustomerIntegralDetail vipCustomerIntegralDetail = jointVipCustomerIntegralDetail(orderRebateRecordVO, orderInfoVO);
                customerIntegralDetailList.add(vipCustomerIntegralDetail);
                CustomerRevenueDetail vipCustomerRevenueDetail = jointVipCustomerRevenueDetail(orderRebateRecordVO, orderInfoVO);
                customerRevenueDetailList.add(vipCustomerRevenueDetail);
            }
        });
        List<CustomerIntegralDetail> customerIntegralDetails = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(customerIntegralDetailList)){
            customerIntegralDetailList.stream().collect(Collectors.groupingBy(CustomerIntegralDetail::getCustomerId))
                    .forEach((k,v) -> {
                        Optional<CustomerIntegralDetail> sum = v.stream().reduce((v1, v2) -> {
                            v1.setIntegral(v1.getIntegral() + v2.getIntegral());
                            return v1;
                        });
                        customerIntegralDetails.add(sum.orElseGet(CustomerIntegralDetail::new));
                    });
        }

        List<CustomerRevenueDetail> customerRevenueDetails = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(customerRevenueDetailList)){
            customerRevenueDetailList.stream().collect(Collectors.groupingBy(CustomerRevenueDetail::getCustomerId))
                    .forEach((k,v) -> {
                        Optional<CustomerRevenueDetail> sum = v.stream().reduce((v1, v2) -> {
                            v1.setAmount(v1.getAmount().add(v2.getAmount()));
                            return v1;
                        });
                        customerRevenueDetails.add(sum.orElseGet(CustomerRevenueDetail::new));
                    });
        }


        if (CollectionUtils.isEmpty(customerIntegralDetails)){
            logger.info("#收益计算# - 该订单无有效收益 orderNo=" + orderInfoVO.getOrderNo());
            return;
        }
        //添加用户积分流水
        customerIntegralDetailService.batchInsert(customerIntegralDetails);
        //添加用户收益流水
        customerRevenueDetailService.batchInsert(customerRevenueDetails);
        //修改钱包
        customerWalletService.modifyCustomerWallet(customerIntegralDetails, customerRevenueDetails, firstCustomerId);
    }

    private CustomerRevenueDetail jointVipCustomerRevenueDetail(OrderRebateRecord orderRebateRecordVO, OrderInfoVO orderInfoVO) {
        CustomerRevenueDetail customerRevenueDetail = new CustomerRevenueDetail();
        customerRevenueDetail.setCustomerId(orderRebateRecordVO.getVipId());
        customerRevenueDetail.setAmount(getNonNullBigDecimal(orderRebateRecordVO.getVipActualProfit()));
        customerRevenueDetail.setOrderCreated(orderInfoVO.getCreated());
        customerRevenueDetail.setOrderNo(orderInfoVO.getOrderNo());
        customerRevenueDetail.setOrderTotal(orderInfoVO.getOtherTotal());
        customerRevenueDetail.setRevenueMethod(CustomerRevenueEnum.METHOD_1.getStatus());
        customerRevenueDetail.setLevel(CustomerRevenueEnum.LEVEL_VIP.getStatus());
        customerRevenueDetail.setType(CustomerRevenueEnum.TYPE_IN.getStatus());
        return customerRevenueDetail;
    }

    private CustomerIntegralDetail jointVipCustomerIntegralDetail(OrderRebateRecord orderRebateRecordVO, OrderInfoVO orderInfoVO) {
        CustomerIntegralDetail customerIntegralDetail = new CustomerIntegralDetail();
        customerIntegralDetail.setCustomerId(orderRebateRecordVO.getVipId());
        customerIntegralDetail.setIntegral(getNonNullInteger(orderRebateRecordVO.getVipActualIntegral()));
        customerIntegralDetail.setOrderCreated(orderInfoVO.getCreated());
        customerIntegralDetail.setOrderNo(orderInfoVO.getOrderNo());
        customerIntegralDetail.setOrderTotal(orderInfoVO.getOtherTotal());
        customerIntegralDetail.setType(CustomerRevenueEnum.TYPE_IN.getStatus());
        customerIntegralDetail.setLevel(CustomerRevenueEnum.LEVEL_VIP.getStatus());
        customerIntegralDetail.setRevenueMethod(CustomerRevenueEnum.METHOD_1.getStatus());
        return customerIntegralDetail;
    }

    private CustomerRevenueDetail jointTwoCustomerRevenueDetail(OrderRebateRecord orderRebateRecordVO, OrderInfoVO orderInfoVO) {
        CustomerRevenueDetail customerRevenueDetail = new CustomerRevenueDetail();
        customerRevenueDetail.setCustomerId(orderRebateRecordVO.getTwoAgentId());
        customerRevenueDetail.setAmount(getNonNullBigDecimal(orderRebateRecordVO.getTwoAgentActualProfit()));
        customerRevenueDetail.setOrderCreated(orderInfoVO.getCreated());
        customerRevenueDetail.setOrderNo(orderInfoVO.getOrderNo());
        customerRevenueDetail.setOrderTotal(orderInfoVO.getOtherTotal());
        customerRevenueDetail.setRevenueMethod(CustomerRevenueEnum.METHOD_1.getStatus());
        customerRevenueDetail.setLevel(CustomerRevenueEnum.LEVEL_AGENT.getStatus());
        customerRevenueDetail.setType(CustomerRevenueEnum.TYPE_IN.getStatus());
        return customerRevenueDetail;
    }

    private CustomerIntegralDetail jointTwoCustomerIntegralDetail(OrderRebateRecord orderRebateRecordVO, OrderInfoVO orderInfoVO) {
        CustomerIntegralDetail customerIntegralDetail = new CustomerIntegralDetail();
        customerIntegralDetail.setCustomerId(orderRebateRecordVO.getTwoAgentId());
        customerIntegralDetail.setIntegral(getNonNullInteger(orderRebateRecordVO.getTwoAgentActualIntegral()));
        customerIntegralDetail.setOrderCreated(orderInfoVO.getCreated());
        customerIntegralDetail.setOrderNo(orderInfoVO.getOrderNo());
        customerIntegralDetail.setOrderTotal(orderInfoVO.getOtherTotal());
        customerIntegralDetail.setType(CustomerRevenueEnum.TYPE_IN.getStatus());
        customerIntegralDetail.setLevel(CustomerRevenueEnum.LEVEL_AGENT.getStatus());
        customerIntegralDetail.setRevenueMethod(CustomerRevenueEnum.METHOD_1.getStatus());
        return customerIntegralDetail;
    }

    private CustomerRevenueDetail jointFirstCustomerRevenueDetail(OrderRebateRecord orderRebateRecordVO, OrderInfoVO orderInfoVO) {
        CustomerRevenueDetail customerRevenueDetail = new CustomerRevenueDetail();
        customerRevenueDetail.setCustomerId(orderRebateRecordVO.getFirstAgentId());
        customerRevenueDetail.setAmount(getNonNullBigDecimal(orderRebateRecordVO.getFirstAgentActualProfit()));
        customerRevenueDetail.setOrderCreated(orderInfoVO.getCreated());
        customerRevenueDetail.setOrderNo(orderInfoVO.getOrderNo());
        customerRevenueDetail.setOrderTotal(orderInfoVO.getOtherTotal());
        customerRevenueDetail.setRevenueMethod(CustomerRevenueEnum.METHOD_1.getStatus());
        customerRevenueDetail.setLevel(CustomerRevenueEnum.LEVEL_AGENT.getStatus());
        customerRevenueDetail.setType(CustomerRevenueEnum.TYPE_IN.getStatus());
        return customerRevenueDetail;
    }

    private CustomerIntegralDetail jointFirstCustomerIntegralDetail(OrderRebateRecord orderRebateRecordVO, OrderInfoVO orderInfoVO) {
        CustomerIntegralDetail customerIntegralDetail = new CustomerIntegralDetail();
        customerIntegralDetail.setCustomerId(orderRebateRecordVO.getFirstAgentId());
        customerIntegralDetail.setIntegral(getNonNullInteger(orderRebateRecordVO.getFirstAgentActualIntegral()));
        customerIntegralDetail.setOrderCreated(orderInfoVO.getCreated());
        customerIntegralDetail.setOrderNo(orderInfoVO.getOrderNo());
        customerIntegralDetail.setOrderTotal(orderInfoVO.getOtherTotal());
        customerIntegralDetail.setType(CustomerRevenueEnum.TYPE_IN.getStatus());
        customerIntegralDetail.setLevel(CustomerRevenueEnum.LEVEL_AGENT.getStatus());
        customerIntegralDetail.setRevenueMethod(CustomerRevenueEnum.METHOD_1.getStatus());
        return customerIntegralDetail;
    }

    private BigDecimal getNonNullBigDecimal(BigDecimal profit) {
        if (Objects.isNull(profit)){
            return BigDecimal.ZERO;
        }
        return profit;
    }

    private Integer getNonNullInteger(Integer integral) {
        if (Objects.isNull(integral)){
            return 0;
        }
        return integral;
    }

    @Override
    public void modifyCustomerRevenueCache(Long customerId, Integer level, CustomerRevenueBO customerRevenueBO) {
        if (Objects.isNull(level) || Integer.valueOf(level).equals(CustomerUserLevelEnum.CUSTOMER_LEVEL_3.getCode())){
            return;
        }
        Byte revenueLevel = getRevenueLevel(level);
        String key = CacheName.CUSTOMER_REVENUE_CACHE + customerId.toString() + "_" + revenueLevel;
        Long ttl = cache.ttl(key);
        cache.set(key, JsonUtil.toJSONString(customerRevenueBO));
        cache.expire(key, Integer.valueOf(ttl.toString()));
    }

    public static Byte getRevenueLevel(Integer level) {
        if (Objects.isNull(level) || Integer.valueOf(level).equals(CustomerUserLevelEnum.CUSTOMER_LEVEL_3.getCode())){
            return null;
        }
        if (Integer.valueOf(level).equals(CustomerUserLevelEnum.CUSTOMER_LEVEL_0.getCode())){
            return CustomerRevenueEnum.LEVEL_VIP.getStatus();
        }
        if (Integer.valueOf(level).equals(CustomerUserLevelEnum.CUSTOMER_LEVEL_1.getCode()) || Integer.valueOf(level).equals(CustomerUserLevelEnum.CUSTOMER_LEVEL_2.getCode())){
            return CustomerRevenueEnum.LEVEL_AGENT.getStatus();
        }
        return null;
    }

    @Override
    public CustomerRevenueBO getCustomerRevenueCache(Long customerId, Integer level) {
        if (Objects.isNull(customerId) || Objects.isNull(level)) {
            return null;
        }
        CustomerRevenueBO customerRevenueBO;
        Byte revenueLevel = getRevenueLevel(level);
        String key = CacheName.CUSTOMER_REVENUE_CACHE + customerId.toString() + "_" + revenueLevel;
        String cacheVal = cache.get(key);
        if (StringUtils.isNotBlank(cacheVal)) {
            customerRevenueBO = JsonUtil.parseJSONObject(cacheVal, CustomerRevenueBO.class);
        } else {
            customerRevenueBO = customerWalletService.getCustomerRevenueByCustomerId(customerId, Integer.valueOf(revenueLevel.toString()));
            cache.set(key, JsonUtil.toJSONString(customerRevenueBO), "NX", "EX", CacheName.CACHE_SECOND);
        }
        return customerRevenueBO;
    }

    @Override
    public CustomerWithdrawalsInfoVO getCustomerWithdrawalsInfo(Long customerId, Integer level) {
        CustomerWithdrawalsInfoVO vo = new CustomerWithdrawalsInfoVO();
        BigDecimal balance = BigDecimal.ZERO;
        BigDecimal remainWithdrawToday = payWithdrawalConfig.getMaxMoney();
        BigDecimal minWithdraw = BigDecimal.ZERO;
        CustomerRevenueBO customerRevenueCache = getCustomerRevenueCache(customerId, level);
        //可用余额
        if (Objects.nonNull(customerRevenueCache)){
            balance = balance.add(customerRevenueCache.getTotalRevenue().subtract(customerRevenueCache.getWithdraw()));
        }
        //今天提现剩余额度
        BigDecimal todayTotalFee = customerWithdrawalsMapper.selectSumTodayTotalFeeByCustomerId(customerId);
        if (Objects.nonNull(todayTotalFee)){
            remainWithdrawToday = remainWithdrawToday.subtract(todayTotalFee);
        }
        //查询商城配置
        ShoppingMallRuleCondition shoppingMallRuleCondition = new ShoppingMallRuleCondition();
        shoppingMallRuleCondition.setSysUserId(customerId);
        ShoppingMallRuleVO shoppingMallRule = shoppingMallRuleService.findShoppingMallRule(shoppingMallRuleCondition);
        if (Objects.nonNull(shoppingMallRule)){
            if (Objects.nonNull(shoppingMallRule.getReflectRule())){
                minWithdraw = minWithdraw.add(shoppingMallRule.getReflectRule());
            }
        }
        vo.setMaxWithdraw(String.format("%.2f",payWithdrawalConfig.getMaxMoney()));
        vo.setBalance(String.format("%.2f",balance));
        vo.setRemainWithdrawToday(String.format("%.2f",remainWithdrawToday));
        vo.setMinWithdraw(String.format("%.2f",minWithdraw));
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void customerWithdrawals(CustomerUser customerUser, CustomerApplyWithDrawCondition condition) {
        Long customerId = customerUser.getCustomerId();
        CustomerUserInfo customerUserInfo = customerUserInfoMapper.selectByPrimaryKey(customerId);
        if (!customerUser.getOpenid().equals(customerUserInfo.getOpenid())){
            throw new BusinessException(BusinessCode.CODE_610026, "门店和微信钱包不匹配");
        }
        if (Objects.isNull(customerUserInfo)){
            throw new BusinessException(BusinessCode.CODE_611112, "查询门店用户信息不存在");
        }
        if (CustomerUserEnum.CUSTOMER_STATUS_0.getCode().equals(customerUserInfo.getStatus())){
            throw new BusinessException(BusinessCode.CODE_611113, "账户已被冻结");
        }
        if (StringUtils.isBlank(customerUserInfo.getCustomerMobile())){
            throw new BusinessException(BusinessCode.CODE_610015, "手机号为空");
        }
        CustomerWithdrawals payWithdrawal = new CustomerWithdrawals();
        payWithdrawal.setSpbillCreateIp(condition.getSpbillCreateIp());
        payWithdrawal.setCustomerId(customerId);
        // 生成提现单号
        payWithdrawal.setWithdrawalsNo(generateWithdrawalsNo());
        BigDecimal totalFee = condition.getTotalFee();
        getWithdrawMoney(customerId, totalFee, customerUser.getLevel());
        payWithdrawal.setTotalFee(totalFee);
        payWithdrawal.setMobile(customerUserInfo.getCustomerMobile());
        payWithdrawal.setFlowDirectionName(CustomerWithdrawalsEnum.FLOW_DIRECTION_TYPE_WEHCHAT.getDesc());
        payWithdrawal.setFlowDirectionType(CustomerWithdrawalsEnum.FLOW_DIRECTION_TYPE_WEHCHAT.getStatus());
        payWithdrawal.setBuyerId(customerUser.getOpenid());
        payWithdrawal.setPaymentAccount(customerUser.getOpenid());
        payWithdrawal.setName(condition.getNick());
        payWithdrawal.setCreatedByName(condition.getNick());
        payWithdrawal.setUpdatedByName(condition.getNick());
        payWithdrawal.setCmmsAmt(BigDecimal.valueOf(0));
        payWithdrawal.setRealFee(condition.getTotalFee());
        payWithdrawal.setRate(BigDecimal.valueOf(0));
        payWithdrawal.setAuditStatus(WithdrawalsStatusEnum.APPLY.getStatusCode());
        payWithdrawal.setCreated(new Date());
        payWithdrawal.setCreatedBy(customerId);
        payWithdrawal.setUpdated(new Date());
        payWithdrawal.setUpdatedBy(customerId);
        payWithdrawal.setCallbackStatus(WithdrawalsStatusEnum.APPLY.getStatusCode());
        customerWithdrawalsMapper.insert(payWithdrawal);

        // 修改钱包余额
        updateCustomerWallet(customerId, condition.getTotalFee(), customerUser.getLevel());

        //发送消息
        sendMessages(payWithdrawal);

    }

    @Override
    public BigDecimal getSumTodayTotalFeeByCustomerId(Long customer) {
        BigDecimal remainWithdrawToday = payWithdrawalConfig.getMaxMoney();
        //今天提现剩余额度
        BigDecimal todayTotalFee = customerWithdrawalsMapper.selectSumTodayTotalFeeByCustomerId(customer);
        if (Objects.nonNull(todayTotalFee)){
            remainWithdrawToday = remainWithdrawToday.subtract(todayTotalFee);
        }
        return remainWithdrawToday;
    }

    private void sendMessages(CustomerWithdrawals payWithdrawal) {
        // 提下完成之后发送小程序消息
        List<MiniTemplateData> data = TemplateData.New().add("keyword1", String.valueOf(payWithdrawal.getTotalFee()))
                .add("keyword2", "提现到微信")
                .add("keyword3", "3-5个工作日")
                .add("keyword4", DateFormatUtils.format(payWithdrawal.getCreated(), "yyyy-MM-dd HH:mm")).getData();
        SendMsgUtil.sendMiniTemplateMsg(messageSendUtils, payWithdrawal.getBuyerId(), "", MiniMsgTypeEnum.WITHDRAWAL_APPLE.getMsgType(), "keyword1.DATA", data);

        // 发送短信消息
        SendMsgUtil.sendSmsMsg(messageSendUtils,payWithdrawal.getMobile(),PayNotifyMsg.STORE_APPLY_WITHDRWAL);
    }

    private void updateCustomerWallet(Long customerId, BigDecimal totalFee, Integer level) {
        //更新缓存
        CustomerRevenueBO customerRevenueCache = getCustomerRevenueCache(customerId, level);
        customerRevenueCache.setBalance(customerRevenueCache.getBalance().subtract(totalFee));
        customerRevenueCache.setWithdraw(customerRevenueCache.getWithdraw().add(totalFee));
        modifyCustomerRevenueCache(customerId, level, customerRevenueCache);

        //修改钱包
        CustomerWallet customerWallet = customerWalletMapper.selectByCustomerIdAndLevel(customerId, level);
        customerWallet.setBalance(customerWallet.getBalance().subtract(totalFee));
        customerWallet.setWithdraw(customerWallet.getWithdraw().add(totalFee));
        customerWalletMapper.updateByPrimaryKey(customerWallet);
    }

    /**
     * 生成提现订单号  格式：T+YYMMDDHH(年月日小时8位)XXXXXXXXX(9位随机吗)= 18位
     *
     * @return
     * @author wangbin
     * @date 2018年8月3日 上午11:34:29
     */
    private String generateWithdrawalsNo() {
        String withdrawalsNo;
        Date date = new Date();
        do {
            UUID uuid = UUID.randomUUID();
            int hashCodeV = (uuid.toString() + System.currentTimeMillis()).hashCode();
            if (hashCodeV < 0) {
                // 有可能是负数
                hashCodeV = -hashCodeV;
            }
            while (hashCodeV > 999999999) {
                hashCodeV = hashCodeV >> 1;
            }
            String withdrawalsNoDateTimeFormatter = "yyMMddHH";
            // 0 代表前面补充0
            // 9 代表长度为4
            // d 代表参数为正数型
            String randomFormat = "%09d";
            withdrawalsNo = "T" + DateFormatUtils.format(date, withdrawalsNoDateTimeFormatter) + String.format(randomFormat, hashCodeV);
        } while (!checkOrderNoAvailable(withdrawalsNo, date));
        return withdrawalsNo;
    }

    /**
     * 校验提现单号生成是否重复
     *
     * @param withdrawalsNo
     * @param date
     * @return
     * @author wangbin
     * @date 2018年8月11日 下午5:32:33
     */
    private boolean checkOrderNoAvailable(String withdrawalsNo, Date date) {

        String withdrawalsNoDateTimeFormatter = "yyMMddHH";
        String val = cache.hget(CacheName.CACHE_KEY_ORDERNO_CHECK_EXISTS + DateFormatUtils.format(date, withdrawalsNoDateTimeFormatter), withdrawalsNo);
        if (org.apache.commons.lang3.StringUtils.isNotBlank(val)) {
            logger.info("用户提现, 订单号生成出现重复：orderNo=[{}]", withdrawalsNo);
            return false;
        } else {
            cache.hset(CacheName.CACHE_KEY_ORDERNO_CHECK_EXISTS + DateFormatUtils.format(date, withdrawalsNoDateTimeFormatter), withdrawalsNo, withdrawalsNo);
            //下一小时就过期
            Long expires = (DateUtils.truncate(DateUtils.addHours(date, 1), Calendar.HOUR_OF_DAY).getTime() - date.getTime()) / 1000;
            cache.expire(CacheName.CACHE_KEY_ORDERNO_CHECK_EXISTS + DateFormatUtils.format(date, withdrawalsNoDateTimeFormatter), expires.intValue());
            return true;
        }
    }

    /** 查询当前账户可提现金额
     * totalFee 当前用户的提现金额*/
    public void getWithdrawMoney(Long customerId, BigDecimal totalFee, Integer level){
        //返回当前账户钱包里的可提现金额
        CustomerRevenueBO revenueBO = getCustomerRevenueCache(customerId, level);
        if(Objects.nonNull(revenueBO)){
            if(revenueBO.getTotalRevenue().compareTo(BigDecimal.valueOf(0L)) <= 0){
                throw new BusinessException(BusinessCode.CODE_610038, "账户没有可提现资金");
            }
            if(totalFee != null && revenueBO.getBalance() != null){
                if(revenueBO.getBalance() .compareTo(totalFee) == -1){
                    throw new BusinessException(BusinessCode.CODE_610035, "当前提现金额不可大于可提现金额");
                }
            }else{
                throw new BusinessException(BusinessCode.CODE_610038, "当前门店没有可提现金额");
            }
        }else{
            throw new BusinessException(BusinessCode.CODE_610038, "账户没有可提现资金");
        }
        logger.info("用户提现, 当前用户可提现信息：customerId=" + customerId + ", 信息=" + JsonUtil.toJSONString(revenueBO));
    }
}
